package com.kinyx.framework.utils;

import java.math.BigDecimal;
import java.math.BigInteger;

import javax.math.YBigDecimal;

import com.kinyx.framework.annotation.assist.CanNotNull;
import com.kinyx.framework.annotation.assist.CanNull;
import com.kinyx.framework.annotation.assist.ReturnNotNull;
import com.kinyx.framework.annotation.assist.ReturnNull;
import com.kinyx.framework.annotation.assist.Throws;
import com.kinyx.framework.enums.impl.ErrorCode0;
import com.kinyx.framework.exception.KRuntimeException;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

/**
 * 数字工具类
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class KNumberUtils {

	/**
	 * 转换为BigDecimal
	 * @param number 数值
	 * @return BigDecimal值
	 */
	@ReturnNull("number == null")
	@Throws(at = "KNumberUtils.toBigDecimal(Object)", value = "ErrorCode0.CanNotConvertType", when = "该类型不可转换")
	public static BigDecimal toBigDecimal(@CanNull final Object number) {
		if (number == null) { return null; }
		if (number instanceof YBigDecimal) { return ((YBigDecimal) number).bigDecimalValue(); }
		if (number instanceof BigInteger) { return new BigDecimal((BigInteger) number); }

		if (number instanceof String) { return new BigDecimal((String) number); }
		if (number instanceof BigDecimal) { return (BigDecimal) number; }

		if (number instanceof Byte) { return new BigDecimal(Byte.toString((Byte) number)); }
		if (number instanceof Short) { return new BigDecimal(Short.toString((Short) number)); }
		if (number instanceof Integer) { return new BigDecimal(Integer.toString((Integer) number)); }
		if (number instanceof Long) { return new BigDecimal(Long.toString((Long) number)); }
		if (number instanceof Float) { return new BigDecimal(Float.toString((Float) number)); }
		if (number instanceof Double) { return new BigDecimal(Double.toString((Double) number)); }

		throw new KRuntimeException(ErrorCode0.CanNotConvertType).param("from", number.getClass().getName()).param("to", BigDecimal.class.getName());
	}

	/**
	 * 取较大值
	 * @param number1 值1
	 * @param number2 值2
	 * @return 较大值
	 */
	@ReturnNotNull
	@Throws(at = "KNumberUtils.toBigDecimal(Object)", value = "ErrorCode0.CanNotConvertType", when = "该类型不可转换")
	public static YBigDecimal max(@CanNotNull final Object number1, @CanNotNull final Object number2) {
		final YBigDecimal bd1 = YBigDecimal.of(number1);
		final YBigDecimal bd2 = YBigDecimal.of(number2);
		return bd1.moreThan(bd2) ? bd1.cloneX() : bd2.cloneX();
	}

	/**
	 * 取较小值
	 * @param number1 值1
	 * @param number2 值2
	 * @return 较小值
	 */
	@ReturnNotNull
	@Throws(at = "KNumberUtils.toBigDecimal(Object)", value = "ErrorCode0.CanNotConvertType", when = "该类型不可转换")
	public static YBigDecimal min(@CanNotNull final Object number1, @CanNotNull final Object number2) {
		final YBigDecimal bd1 = YBigDecimal.of(number1);
		final YBigDecimal bd2 = YBigDecimal.of(number2);
		return bd1.lessThan(bd2) ? bd1.cloneX() : bd2.cloneX();
	}

	/**
	 * 校验取值范围
	 * @param number 值
	 * @param min 最小值。无最小值限制时传入null。
	 * @param max 最大值。无最大值限制时传入null。
	 * @return 校验成功返回封装值
	 */
	@ReturnNotNull
	@Throws(at = "KNumberUtils.toBigDecimal(Object)", value = "ErrorCode0.CanNotConvertType", when = "该类型不可转换")
	@Throws(at = "KNumberUtils.checkRange(Object, Object, Object)", value = "ErrorCode0.ValueMoreThenMaxValue", when = "值大于最大值")
	@Throws(at = "KNumberUtils.checkRange(Object, Object, Object)", value = "ErrorCode0.ValueLessThenMinValue", when = "值小于最小值")
	public static YBigDecimal checkRange(@CanNotNull final Object number, @CanNull final Object min, @CanNull final Object max) {
		final YBigDecimal bd = YBigDecimal.of(number);
		if ((max != null) && bd.moreThan(max)) {
			throw new KRuntimeException(ErrorCode0.ValueMoreThenMaxValue).param("value", bd.toString()).param("maxValue", max.toString());
		}
		if ((min != null) && bd.lessThan(min)) {
			throw new KRuntimeException(ErrorCode0.ValueLessThenMinValue).param("value", bd.toString()).param("minValue", min.toString());
		}
		return bd;
	}

}
